package cn.itsource.user.service.impl;

import cn.itsource.config.RedisService;
import cn.itsource.dto.LoginDto;
import cn.itsource.user.domain.TLogininfo;
import cn.itsource.user.domain.TUser;
import cn.itsource.user.mapper.LogininfoMapper;
import cn.itsource.user.mapper.UserMapper;
import cn.itsource.user.service.ILoginService;
import cn.itsource.utils.AjaxResult;
import cn.itsource.utils.MD5;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
@Transactional
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisService redisService;

    /*
        登录思路：
            补充：功能实现完后，要完善注册功能：注册成功后将用户的信息同步一份到t_logininfo表

            1.先判断用户的状态
            2.如果是0--- 管理员；如果是1---- 用户
            3. 管理员---t_employee ; 用户--- t_user
            4.根据输入帐号和密码进行校验
            5.校验通过后，返回一个“门票”---token令牌

         注意注意注意： 无论是管理员还是用户，它是注册成功后，会同步它的登录信息到统一的表来维护
            t_logininfo
            如果是管理员登录，则直接通过查询t_logininfo表即可验证身份，但是，如果是用户表，则还需要查询保存在t_user中
                对应的salt盐值，才可判断是否成功登录
      */
    @Override
    public AjaxResult account(LoginDto loginDto) {
        //1. 先校验必传参数
        //下面的3个参数，任何一个为空，if返回true
        if (StringUtils.isAnyBlank(loginDto.getUsername(), loginDto.getPassword()) || loginDto.getUserType() == null) {
            return AjaxResult.error().setMessage("缺少必传参数");
        }

        //2. 登录校验： 因为现在t_logininfo表已经 保存了用户的salt盐
        //2.1 先根据登录帐号，查询是否存在这个用户
        Example example = new Example(TLogininfo.class);
        Example.Criteria and = example.and();
        and.orEqualTo("username", loginDto.getUsername())
                .orEqualTo("phone", loginDto.getUsername())
                .orEqualTo("email", loginDto.getUsername());

        TLogininfo tLogininfo = logininfoMapper.selectOneByExample(example);
        if (tLogininfo == null) {
            return AjaxResult.error().setMessage("用户名不正确");
        }
        //2.2 校验密码 ： 如果是平台用户：直接将md5(salt原密码)加密再比较；如果是门户用户：md5（salt+原密码）然后再比较
        //密码加密
        String md_pwd = "";
        if (StringUtils.isNotBlank(tLogininfo.getSalt())) {
            md_pwd = MD5.getMD5(tLogininfo.getSalt() + loginDto.getPassword());
        }else {
            md_pwd = MD5.getMD5(loginDto.getPassword());
        }
        if (StringUtils.equals(md_pwd, tLogininfo.getPassword()) == false) {
            return AjaxResult.error().setMessage("密码不正确");
        }

//        TLogininfo tLogininfo = null;
//        //2. 如果是0--- 管理员；如果是1---- 用户  2021年6月21日：这一步的操作，都是针对登录的用户名和密码的校验工作
//        if (loginDto.getUserType().intValue() == 0) {//管理员
//            //先根据登录帐号（可以是用户名/邮箱/手机号）查询
//            Example example = new Example(TLogininfo.class);
//            Example.Criteria and = example.and();
//            and.orEqualTo("username", loginDto.getUsername())
//                    .orEqualTo("phone", loginDto.getUsername())
//                    .orEqualTo("email", loginDto.getUsername());
//
//            tLogininfo = logininfoMapper.selectOneByExample(example);
//            if (tLogininfo == null) {
//                return AjaxResult.error().setMessage("用户名不正确");
//            }
//            //再校验密码.先将原密码进行md5加密后，再来比较
//            String md5Pwd = MD5.getMD5(loginDto.getPassword());
//            if (!StringUtils.equals(md5Pwd, tLogininfo.getPassword())) {
//                return AjaxResult.error().setMessage("密码不正确");
//            }
//        } else {//如果进到 这里，说明前端用户在登录
//            //此时，如果是前端用户登录，则校验时，应该从t_user进行校验
//            //1.根据用户名查询用户的信息
//            Example example = new Example(TUser.class);
//            example.and().orEqualTo("username", loginDto.getUsername())
//                    .orEqualTo("email", loginDto.getUsername())
//                    .orEqualTo("phone", loginDto.getUsername());
//            //这个方法的意思：根据查询条件，查询并只返回最多一条数据
//            TUser tUser = userMapper.selectOneByExample(example);
//            if (tUser == null) {
//                return AjaxResult.error().setMessage("用户名不存在");
//            }
//            //2.如果用户信息存在，再比较密码（注意：密码加密规则：md5(salt盐+原登录密码)
//            String md_pwd = MD5.getMD5(tUser.getSalt() + loginDto.getPassword());
//            if (StringUtils.equals(md_pwd, tUser.getPassword()) == false) {
//                return AjaxResult.error().setMessage("密码不正确");
//            }
//            //如果用户帐号和密码校验成功，还需要将注册的用户信息，同步一份到t_logininfo表
////
////            tLogininfo = new TLogininfo();
////            tLogininfo.setUsername(loginDto.getUsername());
////            tLogininfo.setPhone(loginDto.getUsername());
////            tLogininfo.setPassword(md_pwd);
////            tLogininfo.setType(true);
////            tLogininfo.setDisable(true);//默认有效
//            //执行保存操作
//            logininfoMapper.insert(tLogininfo);
//        }

        //如果上面的校验都通过，则用户的登录帐号和密码输入正确
        //a. 先生成一个随机的token令牌
        String token = UUID.randomUUID().toString();
        //b. 如果说前端用户在登录后，30分钟内，不在界面中做任何操作，让令牌失效
        //2021年6月22日：token-logininfo信息保存到redis后，目的：在后端的任何地方，需要根据token获取用户信息提供方法
        //以token为key,用户信息为value，保存一份到redis---目的：如果用户60分钟内不进行任何操作，直接token失效
        redisService.setStringKeyAndValue(token, tLogininfo, 60);
        //4 返回AjaxResult，如果登录成功，还需要返回token和loginInfo
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        //为了安全起见，把前台不会用到铭感信息salt和password去空
        tLogininfo.setPassword(null);
        result.put("loginInfo", tLogininfo);

        return AjaxResult.me().setData(result);
    }
}
